/*
 * Copyright 2007 by LongTop Corporation.
 * Softpack ChuangXin Building 15F, XiaMen, FuJian, PRC 361005
 *
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * LongTop Corporation ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with LongTop.
 * 
 */
package com.longtop.framework.util;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

import com.longtop.framework.common.QueryResult;
import com.longtop.framework.security.TransferException;
import com.longtop.intelliweb.common.Log;
import com.longtop.intelliweb.view.Dataset;
import com.longtop.intelliweb.view.Record;

/**
 * intelliWeb数据对象（Dataset,Record）与Java标准对象(List,Collection,JavaBean,Array)互相转换工具类。<br>
 * <p/> 该工具类主要提供以下功能：<br>
 * 1)intelliWeb CustomDataset(自定义数据集)转换成List，Collection或反转<br>
 * 2)intelliWeb CustomDataset的Record转换成javabean或反转<br>
 * 3)PropertyUtils及BeanUtils的常用方法describe,populate,cloneBean,copyProperties,getProperty,setProperty的包装<br>
 * （捕捉错误，发生错误输出到intelliWeb日志中）
 * 
 * @author IntelliWeb Team
 * @version 2.0
 */

public class BeanUtil {

	private static Log log = Log.getLogger(BeanUtil.class);

	/**
	 * 把intelliWeb 的Record对象转换成VO(普通JavaBean)对象，返回转换成功的VO对象。 <p/> 转换时，把Record中的fieldName转成VO(普通JavaBean)的属性名，Record中对应fieldName的value<br>
	 * 转成VO的属性值。 <p/> <b>必须注意：<br>
	 * 1)Record的字段数及字段名必须与VO的属性数及属性名相同。<br>
	 * 2)VO的属性类型可以是简单类型(String,Integer,Double,Date,Boolean等），也可以是Collection或Map，还可以是另一个javabean。 </b>
	 * 
	 * @param record
	 *            intelliWeb Record对象,继承于Map，Map的key为Record的fieldName。<br>
	 * @param bean
	 *            符合规范的JavaBean对象。 符合规范的JavaBean是指：<br>
	 *            1)必须提供一个没有参数的构造函数<br>
	 *            2)必须能够通过getXXX(或isXXX)和setXXX方法访问和修改<br>
	 *            3)get方法不带参数，set方法只带一个成员变量类型参数，并且没有返回值<br>
	 * @param excludeFields
	 *            排除record不转到bean的字段名，多个用逗号隔开
	 * @param indexedPropertyName
	 *            如果bean有类型为list的属性，则为list属性名，否则为null
	 * @param indexedSubPropertyNames
	 *            如果bean有类型为list的t属性，Record中哪些字段属于list对象下的属性，以逗号分隔
	 * @param mappedPropertyName
	 *            如果bean有类型为map的属性，则为map属性名，否则为null
	 * @param mappedSubPropertyNames
	 *            如果bean有类型为map的属性，Record中哪些字段属于map对象下的属性，以逗号分隔
	 * @param nestedPropertyName
	 *            如果bean有类型为nested的属性，则为nested属性名，如果有多级，请用逗号隔开表示。 （如有三级，则为childBean.grandsonBean），否则为null
	 * @param nestedSubPropertyNames
	 *            如果bean有类型为nested的属性， Record中哪些字段属于nested对象下的属性，以逗号分隔
	 * @return 转换成功的VO对象
	 * @throws Exception
	 *             异常基类
	 */
	public static Object recordToVO(Record record, Object bean, String excludeFields, String indexedPropertyName, String indexedSubPropertyNames, String mappedPropertyName, String mappedSubPropertyNames, String nestedPropertyName, String nestedSubPropertyNames) throws Exception {

		if (record == null)
			return null;

		boolean isIndexed = indexedPropertyName != null && indexedSubPropertyNames != null;
		boolean isMapped = mappedPropertyName != null && mappedSubPropertyNames != null;
		boolean isNested = nestedPropertyName != null && nestedSubPropertyNames != null;
		int index = 0;

		try {
			Map map = record.getNewDatasMap();
			Iterator it = map.keySet().iterator();
			String fieldName = "";
			while (it.hasNext()) {
				fieldName = (String) it.next();
				// 排除不转的字段
				if (excludeFields != null && StringUtil.isExist(excludeFields, fieldName)) {
					continue;
				}
				// 如果转成的bean存在列表对象
				if (isIndexed && StringUtil.isExist(indexedSubPropertyNames, fieldName)) {
					PropertyUtils.setIndexedProperty(bean, indexedPropertyName, index, record.getValue(fieldName));
					index++;
					continue;
				}

				// 如果转成的bean存在Map对象
				if (isMapped && StringUtil.isExist(mappedSubPropertyNames, fieldName)) {
					PropertyUtils.setMappedProperty(bean, mappedPropertyName, fieldName, record.getValue(fieldName));
					continue;
				}

				// 如果转成的bean存在嵌套子对象(即bean的成员变量又是一个javabean,如果有多级，请用逗号隔开表示)
				if (isNested && StringUtil.isExist(nestedSubPropertyNames, fieldName)) {
					PropertyUtils.setNestedProperty(bean, nestedPropertyName + "." + fieldName, record.getValue(fieldName));
				}

				// 否则，转成简单javaben对象
				PropertyUtils.setSimpleProperty(bean, fieldName, record.getValue(fieldName));
			}

		} catch (IllegalAccessException e) {
			log.logError("", e);
			throw new IllegalAccessException(e.getMessage());
		} catch (InvocationTargetException e) {
			log.logError("", e);
			throw new InvocationTargetException(e);
		} catch (NoSuchMethodException e) {
			log.logError("", e);
			throw new NoSuchMethodException(e.getMessage());
		}

		return bean;
	}

	public static Object recordToVO(Record record, Object bean) throws Exception {
		return recordToVO(record, bean, null, null, null, null, null, null, null);
	}

	public static Object recordToVO(Record record, Object bean, String excludeFields) throws Exception {
		return recordToVO(record, bean, excludeFields, null, null, null, null, null, null);
	}

	public static Object recordToIndexedVO(Record record, Object bean, String excludeFields, String indexedPropertyName, String indexedSubPropertyNames) throws Exception {
		return recordToVO(record, bean, excludeFields, indexedPropertyName, indexedSubPropertyNames, null, null, null, null);
	}

	public static Object recordToMappedVO(Record record, Object bean, String excludeFields, String mappedPropertyName, String mappedSubPropertyNames) throws Exception {
		return recordToVO(record, bean, excludeFields, null, null, mappedPropertyName, mappedSubPropertyNames, null, null);
	}

	public static Object recordToNestedVO(Record record, Object bean, String excludeFields, String nestedPropertyName, String nestedSubPropertyNames) throws Exception {
		return recordToVO(record, bean, excludeFields, null, null, null, null, nestedPropertyName, nestedSubPropertyNames);
	}

	/**
	 * 把intelliWeb 的Record对象转换成Map对象，返回转换成功的Map对象
	 * 
	 * @param record
	 *            intelliWeb Record对象
	 * @param map
	 *            map,Map的key为Record的fieldName
	 * @return 转换成功的map对象
	 */
	public static Map recordToMap(Record record, Map map) {

		if (record == null)
			return null;
		map = record.getNewDatasMap();
		return map;
	}

	/**
	 * 转换CustomDataset的当前记录转换成VO(普通JavaBean)对象，返回转换成功的VO对象
	 * 
	 * @param dataset
	 *            intelliWeb CustomDataset
	 * @param beanClass
	 *            符合规范的JavaBean对象的类型
	 * @return 转换成功的VO对象
	 * @throws Exception
	 *             如果转换失败，则返回null
	 * @update:SJH
	 */
	public static <T> T datasetToVO(Dataset dataset, Class beanClass) throws Exception {
		return datasetToVO(dataset, beanClass, null);
	}

	/**
	 * 转换CustomDataset的当前记录转换成VO(普通JavaBean)对象，返回转换成功的VO对象
	 * 
	 * @param dataset
	 *            intelliWeb CustomDataset
	 * @param beanClass
	 *            符合规范的JavaBean对象的类型
	 * @param excludeFields
	 *            排除record不转到bean的字段名，多个用逗号隔开
	 * @return 转换成功的VO对象
	 * @throws Exception
	 *             如果转换失败，则返回null
	 * @update:SJH
	 */
	public static <T> T datasetToVO(Dataset dataset, Class beanClass, String excludeFields) throws Exception {
		if (dataset == null)
			return null;
		Record record = dataset.getCurrentRecord();
		Object bean = beanClass.newInstance();
		if (record != null)
			return (T) recordToVO(dataset.getCurrentRecord(), bean, excludeFields);
		else
			return null;
	}

	/**
	 * 转换List对象(每个成员为简单javabean或Map)成CustomDataset，返回转换成功的CustomDataset
	 * 
	 * @param list
	 *            list对象，list成员为Map或javabean。
	 * @param dataset
	 *            CustomDataset对象
	 * @param isAppend
	 *            是否把list追加到dataset后面，true：是(默认)，false:否，先清除dataset现有值，再追加
	 * @return CustomDataset 转换成功的CustomDataset对象
	 */
	public static Dataset listToDataset(List list, Dataset dataset, boolean isAppend) {
		if (list == null || dataset == null)
			return dataset;
		if (!isAppend)
			dataset.clear();
		int size = list.size();
		for (int j = 0; j < size; j++) {
			dataset.appendObject(list.get(j));
		}
		return dataset;
	}

	/**
	 * 转换List对象成CustomDataset（追加到CustomDataset后面），返回转换成功的CustomDataset
	 * 
	 * @param list
	 *            list对象，list成员为Map或javabean。
	 * @param dataset
	 *            CustomDataset对象
	 * @return CustomDataset 转换成功的CustomDataset对象
	 */
	public static Dataset listToDataset(List list, Dataset dataset) {
		return listToDataset(list, dataset, true);
	}

	/**
	 * 把集合对象转为CustomDataset对象。集合对象可以为:List,Collection,Array
	 * 
	 * @param collection
	 *            集合对象，可以为:List,Collection,Array
	 * @param dataset
	 *            CustomDataset对象
	 * @param isAppend
	 *            是否把collection追加到dataset后面，true：是(默认)，false:否，先清除dataset现有值，再追加
	 * @return CustomDataset 转换成功的CustomDataset对象
	 */
	public static Dataset collectionToDataset(Object collection, Dataset dataset, boolean isAppend) {
		if (collection == null)
			return dataset;
		if (!isAppend)
			dataset.clear();
		int intSize = 0;
		if (collection instanceof List) {
			List list = (List) collection;
			intSize = list.size();
			for (int j = 0; j < intSize; j++) {
				dataset.appendObject(list.get(j));
			}

		} else if (collection instanceof Collection) {
			Collection collection1 = (Collection) collection;
			for (Iterator iterator = collection1.iterator(); iterator.hasNext();) {
				collection1 = (Collection) iterator.next();
				dataset.appendObject(collection1);
			}

		} else if (collection.getClass().isArray()) {
			Object aobj[];
			intSize = (aobj = (Object[]) collection).length;
			for (int k = 0; k < intSize; k++) {
				dataset.appendObject(aobj[k]);
			}

		} else {
			dataset.appendObject(collection);
		}
		return dataset;
	}

	/**
	 * 把集合对象转为Dataset对象。
	 * 
	 * @param queryResult
	 *            查询结果集合
	 * @param dataset
	 *            Dataset对象
	 * @param isAppend
	 *            是否把collection追加到dataset后面，true：是(默认)，false:否，先清除dataset现有值，再追加
	 * @param setTotalSize
	 *            是否自动设置dataset的总记录数.为true时自动设置查询的总记录数,否则不执行.
	 * @return Dataset 转换成功的Dataset对象
	 */
	public static Dataset queryResultToDataset(QueryResult queryResult, Dataset dataset, boolean isAppend, boolean setTotalSize) {
		collectionToDataset(queryResult.getResultList(), dataset, isAppend);
		if (setTotalSize) {
			dataset.setTotalSize(queryResult.getTotalRecordNumber());
		}

		return dataset;
	}

	/**
	 * 把集合对象转为CustomDataset对象（追加到CustomDataset后面）。集合对象可以为:List,Collection,Array
	 * 
	 * @param collection
	 *            集合对象，可以为:List,Collection,Array
	 * @param dataset
	 *            CustomDataset对象
	 * @return CustomDataset 转换成功的CustomDataset对象
	 */
	public static Dataset collectionToDataset(Object collection, Dataset dataset) {
		return collectionToDataset(collection, dataset, true);
	}

	/**
	 * 转化dataset到list对象，list的每个成员类型由class指定
	 * 
	 * @param dataset
	 *            CustomDataset对象
	 * @param beanClass
	 *            list的成员类型，如IwbFrameLog.class
	 * @param excludeFields
	 *            排除record不转到bean的字段名，多个用逗号隔开
	 * @return List 转化成功的list对象
	 * @throws TransferException
	 *             转换失败
	 */
	public static List datasetToList(Dataset dataset, Class beanClass, String excludeFields) {
		if (dataset == null)
			return null;
		List list = new ArrayList();
		Object bean = null;
		Record record = null;
		try {
			dataset.moveBeforeFirst();
			while (dataset.hasNext()) {
				// 创建一个实体bean
				bean = beanClass.newInstance();
				// 取得当前记录
				record = dataset.moveNext();
				// 把当前记录有效数据转成bean
				recordToVO(record, bean, excludeFields);
				// populate(bean, record);
				// 把转换成功的bean添加到list
				list.add(bean);
			}
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
		return list;
	}

	public static List datasetToList(Dataset dataset, Class beanClass) {
		return datasetToList(dataset, beanClass, null);
	}

	/**
	 * 转化dataset中变化的记录到list对象，list的每个成员类型由class指定。
	 * 
	 * @param dataset
	 *            CustomDataset对象
	 * @param beanClass
	 *            list的成员类型，如IwbFrameLog.class
	 * @param excludeFields
	 *            排除record不转到bean的字段名，多个用逗号隔开
	 * @return List 转化成功的list对象
	 * @throws TransferException
	 *             转换失败
	 */
	public static List datasetChangedToList(Dataset dataset, Class beanClass, String excludeFields) {
		if (dataset == null)
			return null;
		List list = new ArrayList();
		Object bean = null;
		Record record = null;
		try {
			dataset.moveBeforeFirst();
			while (dataset.hasNext()) {
				// 取得当前记录
				record = dataset.moveNext();
				// 没有变化的记录不转换
				if (record.getState() == Record.STATE_NONE) {
					continue;
				}
				// 创建一个实体bean
				bean = beanClass.newInstance();
				// 把当前记录有效数据转成bean
				recordToVO(record, bean, excludeFields);
				// 把转换成功的bean添加到list
				list.add(bean);
			}
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
		return list;
	}

	/**
	 * 转化dataset中指定状态的记录到list对象，list的每个成员类型由class指定。
	 * 
	 * @param dataset
	 *            CustomDataset对象
	 * @param beanClass
	 *            list的成员类型，如IwbFrameLog.class
	 * @param excludeFields
	 *            排除record不转到bean的字段名，多个用逗号隔开
	 * @param status
	 *            记录状态 Record.STATUS_DELETE,Record.STATUS_INSERT, Record.STATUS_UPDATE,Record.STATUS_NONE
	 * @return List 转化成功的list对象
	 * @throws TransferException
	 *             转换失败
	 */
	public static List datasetStatusToList(Dataset dataset, Class beanClass, String excludeFields, int[] status) {

		if (dataset == null)
			return null;
		List list = new ArrayList();
		Object bean;
		Record record;
		try {
			dataset.moveBeforeFirst();
			while (dataset.hasNext()) {
				// 取得当前记录
				record = dataset.moveNext();
				// 没有变化的记录不转换
				if (!isExistStatus(status, record.getState())) {
					continue;
				}
				// 创建一个实体bean
				bean = beanClass.newInstance();
				// 把当前记录有效数据转成bean
				recordToVO(record, bean, excludeFields);
				// 把转换成功的bean添加到list
				list.add(bean);
			}
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
		return list;
	}

	public static boolean isExistStatus(int[] statusList, int status) {
		for (int i = 0; i < statusList.length; i++) {
			if (status == statusList[i]) {
				return true;
			}
		}
		return false;
	}

	public static List datasetChangedToList(Dataset dataset, Class beanClass) {
		return datasetChangedToList(dataset, beanClass, null);
	}

	public static List datasetStatusToList(Dataset dataset, Class beanClass, int[] status) {
		return datasetStatusToList(dataset, beanClass, null, status);
	}

	/**
	 * 转化dataset中选中的记录到list对象，list的每个成员类型由class指定。
	 * 
	 * @param dataset
	 *            CustomDataset对象
	 * @param beanClass
	 *            list的成员类型，如IwbFrameLog.class
	 * @param excludeFields
	 *            排除record中不转的字段名
	 * @param selectedFieldName
	 *            用于标识选择的字段名
	 * @param selectedFieldValue
	 *            用于标识选中的字段值
	 * @return List 转化成功的list对象
	 * @throws TransferException
	 *             转换失败
	 */
	public static List datasetSelectedToList(Dataset dataset, Class beanClass, String excludeFields, String selectedFieldName, String selectedFieldValue) {
		if (dataset == null)
			return null;
		List list = new ArrayList();
		Object bean = null;
		Record record = null;
		selectedFieldName = selectedFieldName == null ? "selected" : selectedFieldName;
		selectedFieldValue = selectedFieldValue == null ? "1" : selectedFieldValue;

		try {
			dataset.moveBeforeFirst();
			while (dataset.hasNext()) {
				// 取得当前记录
				record = dataset.moveNext();
				if (record.getString(selectedFieldName).equals(selectedFieldValue)) {
					// 创建一个实体bean
					bean = beanClass.newInstance();
					// 把当前记录有效数据转成bean
					recordToVO(record, bean, excludeFields);
					// 把转换成功的bean添加到list
					list.add(bean);
				}
			}
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
		return list;
	}

	public static List datasetSelectedToList(Dataset dataset, Class beanClass) {
		return datasetSelectedToList(dataset, beanClass, null, null, null);
	}

	/**
	 * 复制对象(源对象中值为null的键值不复制到目标对象) 验证(不能达到效果):杨向阳
	 * 
	 * @param dest
	 *            目标对象
	 * @param src
	 *            源对象
	 */
	public static void copyObject(Object dest, Object src) {
		try {
			Map m = BeanUtils.describe(src);
			Map d = new HashMap();
			for (Iterator iter = m.entrySet().iterator(); iter.hasNext();) {
				Map.Entry element = (Map.Entry) iter.next();
				if (element.getValue() != null)
					d.put(element.getKey(), element.getValue());
			}
			BeanUtils.populate(dest, d);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 复制对象属性
	 * 
	 * @param dest
	 *            目标对象
	 * @param src
	 *            源对象
	 */
	public static void copyProperties(Object dest, Object src) {
		try {
			BeanUtils.copyProperties(dest, src);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 获取bean的属性的值，返回属性值字符串
	 * 
	 * @param bean
	 *            要获取属性的bean
	 * @param propertyName
	 *            属性名
	 * @return String 获取的属性值
	 */
	public static String getProperty(Object bean, String propertyName) {
		try {
			return BeanUtils.getProperty(bean, propertyName);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 设置bean的属性值
	 * 
	 * @param bean
	 *            要设置属性的bean
	 * @param propertyName
	 *            属性名
	 * @param value
	 *            属性值
	 */
	public static void setProperty(Object bean, String propertyName, Object value) {
		try {
			BeanUtils.setProperty(bean, propertyName, value);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 获取bean的属性的值，返回属性值对象
	 * 
	 * @param bean
	 *            要获取属性的bean
	 * @param propertyName
	 *            属性名
	 * @return Object 获取的属性值
	 */
	public static Object getObjectProperty(Object bean, String propertyName) {
		try {
			return PropertyUtils.getProperty(bean, propertyName);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 克隆bean对象。<br>
	 * 
	 * @param bean
	 *            要克隆的bean对象，必须是提供一系列的成员变量及get/set方法。<br>
	 *            如果该get/set方法是私有或没有相应的get/set方法，则不会对该成员变量进行复制。
	 * @return 克隆的对象
	 */
	public static Object cloneBean(Object bean) {
		try {
			return BeanUtils.cloneBean(bean);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 转化bean到map。bean的属性名转化为map的key，属性值转化为map的value
	 * 
	 * @param bean
	 *            要转化的bean
	 * @return 返回转化成功的
	 */
	public static Map describe(Object bean) {

		try {
			return PropertyUtils.describe(bean);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 转化map到bean。 map的key转化为bean的属性名，map的value转化bean的属性值
	 * 
	 * @param bean
	 *            转化后的bean
	 * @param map
	 *            要转化的map
	 */
	public static void populate(Object bean, Map map) {
		try {
			BeanUtils.populate(bean, map);
		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
	}

	/**
	 * 去掉bean属性值中的空格
	 * 
	 * @param bean
	 *            bean对象
	 * @return 去掉属性值后空格的bean
	 */
	public static Object trim(Object bean) {
		if (bean == null)
			return null;
		try {
			Map map = null;

			if (bean instanceof Map)
				map = (Map) bean;
			else
				map = PropertyUtils.describe(bean);

			Iterator it = map.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry entry = (Map.Entry) it.next();
				if ((entry.getValue() != null) && (entry.getValue() instanceof String)) {
					entry.setValue(entry.getValue().toString().trim());
					// 如果仅去除右边空格，则用下面方法
					// entry.setValue(StringUtil.trimRight(entry.getValue().toString()));
				}
			}

			if (!(bean instanceof Map))
				PropertyUtils.copyProperties(bean, map);

		} catch (Throwable e) {
			log.logError(e);
			throw new TransferException(e);
		}
		return bean;
	}

	/**
	 * 去掉list成员中bean属性值中的空格
	 * 
	 * @param list
	 *            列表对象
	 * @return list 去掉list成员中bean属性值中的空格后的list
	 */
	public static List trim(List list) {
		if (list == null || list.size() == 0) {
			return list;
		}

		Iterator it = list.iterator();
		while (it.hasNext()) {
			trim(it.next());
		}
		return list;
	}

}
